﻿#include "sys_inc.h"
#include "ff.h"
#include "ebook_api.h"
#include "ebook_init.h"
#include "ebook_format.h"

#ifdef _WIN32
#include "ff_unicode.h"
WCHAR ff_covert_func(	/* Converted code, 0 means conversion error */
	WCHAR	chr,	/* Character code to be converted */
	UINT	dir		/* 0: Unicode to OEM code, 1: OEM code to Unicode */
	)
{
	WCHAR c = 0;

#if FF_CODE_PAGE == 936
	int i = 0, n = 0, li = 0, hi = 0;
	const WCHAR* p = NULL;
#endif
	//Debug_printf(DISP_KEY_FF,"ff_covert_func: chr=0x%x.dir=%d \r\n",chr,dir);
	if (chr < 0x80) {	/* ASCII */
		c = chr;
	}
#if FF_CODE_PAGE == 936
	else {
		if (dir) {		/* OEM code to unicode */
			p = oem2uni936;
			hi = sizeof(oem2uni936) / 4 - 1;
		}
		else {		/* Unicode to OEM code */
			//p = uni2oem936;
			//hi = sizeof(uni2oem936) / 4 - 1;
		}
		li = 0;
		for (n = 16; n; n--) {
			i = li + (hi - li) / 2;
			if (chr == p[i * 2]) break;
			if (chr > p[i * 2])
				li = i;
			else
				hi = i;
		}
		c = n ? p[i * 2 + 1] : 0;
	}
#endif
	return c;
}
#else
extern const unsigned short oem2uni936[];
extern  WCHAR ff_covert_func (	/* Converted code, 0 means conversion error */
	WCHAR	chr,	/* Character code to be converted */
	UINT	dir		/* 0: Unicode to OEM code, 1: OEM code to Unicode */
);
#endif


uint16_t ebook_SearchCodeTable_GB2312(uint16_t gbKey)
{
	uint16_t gb_temp_key = gbKey;
	gb_temp_key = gb_temp_key >> 8;
	if (gb_temp_key < 0xA1) // can`t transfer to 2312table
	{
		//Debug_printf(DISP_KEY_MSCAN, "no unicode key replay.\r\n");
		return 0;
	}
	return ff_covert_func(gbKey, 1);
}

uint16_t ebook_gb2312_to_utf8_func(const unsigned char* source_buf, uint16_t source_buf_len, uint8_t* real_buf, uint32_t buf_space)
{
	uint16_t sur_buf_offset = 0;
	uint16_t obj_buf_offset = 0;
	uint16_t byteCount = 0;
	uint16_t gbKey = 0;
	uint32_t unicodeKey = 0;

	while (sur_buf_offset < source_buf_len)
	{
		memcpy(&gbKey, (source_buf + sur_buf_offset), 2);
		gbKey = (gbKey >> 8) | (gbKey << 8);
		unicodeKey = ebook_SearchCodeTable_GB2312(gbKey);
		obj_buf_offset += byteCount;
		byteCount = 0;

		if (unicodeKey == 0)
		{
			real_buf[obj_buf_offset] = source_buf[sur_buf_offset];
			obj_buf_offset++;
		}
		else
		{
			if (unicodeKey <= 0x0000007F)
			{
				real_buf[obj_buf_offset] = unicodeKey & 0x7F;
				byteCount = 1;
				sur_buf_offset++;
				//Debug_printf(DISP_KEY_MSCAN, "unicodeKey<=0x0000007F.\r\n");
				continue;
			}
			else if (unicodeKey >= 0x00000080 && unicodeKey < 0x000007FF)
			{
				real_buf[obj_buf_offset + 1] = (unicodeKey & 0x3F) | 0x80;
				real_buf[obj_buf_offset] = ((unicodeKey >> 6) & 0x1F) | 0xC0;
				byteCount = 2;
				sur_buf_offset += 2;
				//Debug_printf(DISP_KEY_MSCAN, "unicodeKey>=0x00000080&&unicodeKey<0x000007FF.\r\n");
				continue;
			}
			else if (unicodeKey >= 0x00000800 && unicodeKey <= 0x0000FFFF)
			{
				real_buf[obj_buf_offset + 2] = (unicodeKey & 0x3F) | 0x80;
				real_buf[obj_buf_offset + 1] = ((unicodeKey >> 6) & 0x3F) | 0x80;
				real_buf[obj_buf_offset] = ((unicodeKey >> 12) & 0x0F) | 0xE0;
				byteCount = 3;
				sur_buf_offset += 2;
				//Debug_printf(DISP_KEY_MSCAN, "unicodeKey>=0x00000800&&unicodeKey<=0x0000FFFF.\r\n");
				continue;
			}
			else if (unicodeKey >= 0x00010000 && unicodeKey <= 0x0010FFFF)
			{
				real_buf[obj_buf_offset + 3] = (unicodeKey & 0x3F) | 0x80;
				real_buf[obj_buf_offset + 2] = ((unicodeKey >> 6) & 0x3F) | 0x80;
				real_buf[obj_buf_offset + 1] = ((unicodeKey >> 12) & 0x3F) | 0x80;
				real_buf[obj_buf_offset] = ((unicodeKey >> 18) & 0xF7);
				byteCount = 4;
				//Debug_printf(DISP_KEY_MSCAN, "unicodeKey>=0x00010000&&unicodeKey<=0x0010FFFF.\r\n");
				continue;
			}
			else if (unicodeKey >= 0x00200000 && unicodeKey <= 0x03FFFFFF)
			{
				real_buf[obj_buf_offset + 4] = (unicodeKey & 0x3F) | 0x80;
				real_buf[obj_buf_offset + 3] = ((unicodeKey >> 6) & 0x3F) | 0x80;
				real_buf[obj_buf_offset + 2] = ((unicodeKey >> 12) & 0x3F) | 0x80;
				real_buf[obj_buf_offset + 1] = ((unicodeKey >> 18) & 0x3F) | 0x80;
				real_buf[obj_buf_offset] = ((unicodeKey >> 24) & 0xF7);
				byteCount = 5;
				//Debug_printf(DISP_KEY_MSCAN, "unicodeKey>=0x00200000&&unicodeKey<=0x03FFFFFF.\r\n");
				continue;
			}
			else if (unicodeKey >= 0x04000000 && unicodeKey <= 0x7FFFFFFF)
			{
				real_buf[obj_buf_offset + 5] = (unicodeKey & 0x3F) | 0x80;
				real_buf[obj_buf_offset + 4] = ((unicodeKey >> 6) & 0x3F) | 0x80;
				real_buf[obj_buf_offset + 3] = ((unicodeKey >> 12) & 0x3F) | 0x80;
				real_buf[obj_buf_offset + 2] = ((unicodeKey >> 18) & 0x3F) | 0x80;
				real_buf[obj_buf_offset + 1] = ((unicodeKey >> 24) & 0x3F) | 0x80;
				real_buf[obj_buf_offset] = ((unicodeKey >> 30) & 0xF7);
				byteCount = 6;
				//Debug_printf(DISP_KEY_MSCAN, "unicodeKey>=0x04000000&&unicodeKey<=0x7FFFFFFF.\r\n");
				continue;
			}
			else
			{
				//Debug_printf(DISP_KEY_MSCAN, "unicodeKey  unicodeKey  default.\r\n");
				Debug_printf(DISP_KEY_MSCAN, "out of unicodeKey.\r\n");
				continue;
			}
		}
		obj_buf_offset += byteCount;
		sur_buf_offset++;

		if (obj_buf_offset >= buf_space)
		{
			Debug_printf(DISP_KEY_MSCAN, "ebook_gb2312_to_utf8_func error. real_len >= buf_space.\r\n");
			return 0;
		}
	}
	
	return obj_buf_offset;
}

uint8_t ebook_format_check_string(const unsigned char* check_buf, uint32_t buf_length)
{
	uint32_t i = 0;

	if (buf_length == 0)
	{
		return ERROR_FORMAT;
	}

	if(buf_length >= 4)
	{
		uint32_t bom = 0;
		bom |= check_buf[0]<<24;
		bom |= check_buf[1]<<16;
		bom |= check_buf[2]<<8;
		bom |= check_buf[3]<<0;

		if (bom == 0x0000FEFF)
		{
			return UTF_32_B_ENDIAN_FORMAT;
		}
		else if (bom == 0xFFFE0000)
		{
			return UTF_32_L_ENDIAN_FORMAT;
		}
		else if (bom >= 0xFEFF0001 && bom <= 0xFEFFFFFF)
		{
			return UTF_16_B_ENDIAN_FORMAT;
		}
		else if (bom >= 0xFFFE0001 && bom <= 0xFFFEFFFF)
		{
			return UTF_16_L_ENDIAN_FORMAT;
		}
		else if (bom >= 0xEFBBBF00 && bom <= 0xEFBBBFFF)
		{
			return UTF_8_BOM_FORMAT;
		}
		else
		{
			;//continue
		}
	}

	i = 0;
	while(i < buf_length)
	{
		uint8_t c = check_buf[i];

		if (c >= 0xF8)
		{
			return ERROR_FORMAT;
		}
		else if (c >= 0xF0)
		{
			if ( (check_buf[i+1] < 0x80 || check_buf[i+1] >= 0xC0) &&
				 (check_buf[i+2] < 0x80 || check_buf[i+2] >= 0xC0) &&
				 (check_buf[i+3] < 0x80 || check_buf[i+3] >= 0xC0) )
			{
				return ANSI_FORMAT;
			}
			i+=4;
		}
		else if (c >= 0xE0)
		{
			if ( (check_buf[i+1] < 0x80 || check_buf[i+1] >= 0xC0) &&
				 (check_buf[i+2] < 0x80 || check_buf[i+2] >= 0xC0) )
			{
				return ANSI_FORMAT;
			}
			i+=3;
		}
		else if (c >= 0xC0)
		{
			if (check_buf[i+1] < 0x80 || check_buf[i+1] >= 0xC0)
			{
				return ANSI_FORMAT;
			}
			i+=2;
		}
		else if (c >= 0x80)
		{
			i+=2;
		}
		else
		{
			i++;
		}
	}

	return UTF_8_NOBOM_FORMAT;
}
